home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.3 (Developer)…68k, x86, SPARC, PA-RISC] / NeXTSTEP 3.3 Dev Intel.iso / NextDeveloper / Source / GNU / emacs / cpp / cccp.c next >
C/C++ Source or Header  |  1990-09-28  |  65KB  |  2,484 lines

  1. /* C Compatible Compiler Preprocessor (CCCP)
  2. Copyright (C) 1986, Free Software Foundation, Inc.
  3.                     Written by Paul Rubin, June 1986
  4.  
  5.                NO WARRANTY
  6.  
  7.   BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
  8. NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW.  EXCEPT
  9. WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
  10. RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
  11. WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
  12. BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  13. FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY
  14. AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE
  15. DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
  16. CORRECTION.
  17.  
  18.  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
  19. STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
  20. WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
  21. LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
  22. OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
  23. USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
  24. DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
  25. A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
  26. PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
  27. DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
  28.  
  29.         GENERAL PUBLIC LICENSE TO COPY
  30.  
  31.   1. You may copy and distribute verbatim copies of this source file
  32. as you receive it, in any medium, provided that you conspicuously
  33. and appropriately publish on each copy a valid copyright notice
  34. "Copyright (C) 1986 Free Software Foundation"; and include
  35. following the copyright notice a verbatim copy of the above disclaimer
  36. of warranty and of this License.
  37.  
  38.   2. You may modify your copy or copies of this source file or
  39. any portion of it, and copy and distribute such modifications under
  40. the terms of Paragraph 1 above, provided that you also do the following:
  41.  
  42.     a) cause the modified files to carry prominent notices stating
  43.     that you changed the files and the date of any change; and
  44.  
  45.     b) cause the whole of any work that you distribute or publish,
  46.     that in whole or in part contains or is a derivative of this
  47.     program or any part thereof, to be licensed at no charge to all
  48.     third parties on terms identical to those contained in this
  49.     License Agreement (except that you may choose to grant more extensive
  50.     warranty protection to some or all third parties, at your option).
  51.  
  52.     c) You may charge a distribution fee for the physical act of
  53.     transferring a copy, and you may at your option offer warranty
  54.     protection in exchange for a fee.
  55.  
  56. Mere aggregation of another unrelated program with this program (or its
  57. derivative) on a volume of a storage or distribution medium does not bring
  58. the other program under the scope of these terms.
  59.  
  60.   3. You may copy and distribute this program (or a portion or derivative
  61. of it, under Paragraph 2) in object code or executable form under the terms
  62. of Paragraphs 1 and 2 above provided that you also do one of the following:
  63.  
  64.     a) accompany it with the complete corresponding machine-readable
  65.     source code, which must be distributed under the terms of
  66.     Paragraphs 1 and 2 above; or,
  67.  
  68.     b) accompany it with a written offer, valid for at least three
  69.     years, to give any third party free (except for a nominal
  70.     shipping charge) a complete machine-readable copy of the
  71.     corresponding source code, to be distributed under the terms of
  72.     Paragraphs 1 and 2 above; or,
  73.  
  74.     c) accompany it with the information you received as to where the
  75.     corresponding source code may be obtained.  (This alternative is
  76.     allowed only for noncommercial distribution and only if you
  77.     received the program in object code or executable form alone.)
  78.  
  79. For an executable file, complete source code means all the source code for
  80. all modules it contains; but, as a special exception, it need not include
  81. source code for modules which are standard libraries that accompany the
  82. operating system on which the executable file runs.
  83.  
  84.   4. You may not copy, sublicense, distribute or transfer this program
  85. except as expressly provided under this License Agreement.  Any attempt
  86. otherwise to copy, sublicense, distribute or transfer this program is void and
  87. your rights to use the program under this License agreement shall be
  88. automatically terminated.  However, parties who have received computer
  89. software programs from you with this License Agreement will not have
  90. their licenses terminated so long as such parties remain in full compliance.
  91.  
  92.  In other words, you are welcome to use, share and improve this program.
  93.  You are forbidden to forbid anyone else to use, share and improve
  94.  what you give them.   Help stamp out software-hoarding!  */
  95.  
  96. typedef unsigned char U_CHAR;
  97.  
  98. #ifdef EMACS
  99. #define NO_SHORTNAMES
  100. #include "../src/config.h"
  101. #ifdef static
  102. #undef static
  103. #endif
  104. #ifdef open
  105. #undef open
  106. #undef close
  107. #undef read
  108. #undef write
  109. #endif /* open */
  110. #endif /* EMACS */
  111.  
  112. #include <sys/types.h>
  113. #include <sys/stat.h>
  114. #include <sys/file.h>
  115. #include <ctype.h>
  116. #include <stdio.h>
  117. #ifndef USG
  118. #include <sys/time.h>        /* for __DATE__ and __TIME__ */
  119. #else
  120. #define index strchr
  121. #define rindex strrchr
  122. #include <time.h>
  123. #include <fcntl.h>
  124. #endif /* USG */
  125.  
  126. void bcopy (), bzero ();
  127. int bcmp ();
  128.  
  129. char *xmalloc (), *xrealloc (), *xcalloc ();
  130. void fatal (), pfatal_with_name (), perror_with_name ();
  131.  
  132. char *progname;
  133.  
  134. #define FATAL_EXIT_CODE 33    /* gnu cc command understands this */
  135.  
  136. struct directory_stack
  137.   {
  138.     struct directory_stack *next;
  139.     char *fname;
  140.   };
  141.  
  142. /* #include "file" starts with the first entry in the stack */
  143. /* #include <file> starts with the second. */
  144. /* -I directories are added after the first */
  145. struct directory_stack default_includes[2] =
  146.   {
  147.     { &default_includes[1], "." },
  148.     { 0, "/usr/include" }
  149.   };
  150. struct directory_stack *include = &default_includes[0];
  151.  
  152. int max_include_len = 14;    /* strlen (default_include) + 2
  153.                             (for / and null) */
  154.  
  155. char STDIN_FILE[] = "";        /* Empty, like real cpp */
  156. int put_out_comments = 0;    /* JF non-zero means leave comments in the
  157.                    output file.  Used by lint */
  158.  
  159. /* table to tell if char can be part of a C identifier. */
  160. U_CHAR is_idchar[256];
  161. /* table to tell if char can be first char of a c identifier. */
  162. U_CHAR is_idstart[256];
  163. /* table to tell if c is horizontal space.  isspace() thinks that
  164.    newline is space; this is not a good idea for this program. */
  165. U_CHAR is_hor_space[256];
  166.  
  167. /* I/O buffer structure.  Ought to be used for the output file too.
  168.    These are also used when there is no file present, for example,
  169.    when rescanning a definition.  Then, the fname field is null. */
  170. #define INPUT_STACK_MAX 100
  171. struct file_buf {
  172.   struct infile *next;    /* for making stacks of file ptrs */
  173.   char *fname;
  174.   int lineno;
  175.   int length;
  176.   U_CHAR *buf;
  177.   U_CHAR *bufp;
  178. } instack[INPUT_STACK_MAX];
  179. int indepth = 0;
  180.  
  181. typedef struct file_buf FILE_BUF;
  182.  
  183. /* The output buffer.  Its LENGTH field is the amount of room allocated
  184.    for the buffer, not the number of chars actually present.  To get
  185.    that, subtract outbuf.buf from outbuf.bufp. */
  186.  
  187. #define OUTBUF_SIZE 10    /* initial size of output buffer */
  188. FILE_BUF outbuf;
  189.  
  190. /* Structure allocated for every #define.  For a simple replacement
  191.    such as
  192.        #define foo bar ,
  193.    nargs = -1, the `pattern' list is null, and the expansion is just
  194.    the replacement text.  Nargs = 0 means a real macro with no args,
  195.    e.g.,
  196.        #define getchar() getc(stdin) .
  197.    When there are args, the expansion is the replacement text with the
  198.    args squashed out, and the reflist is a list describing how to
  199.    build the output from the input: e.g., "3 chars, then the 1st arg,
  200.    then 9 chars, then the 3rd arg, then 0 chars, then the 2nd arg".
  201.    The chars here come from the expansion.  Thus, for any definition
  202.    d , strlen(d->expansion) should equal the sum of all the
  203.    d->pattern->nchars.  Note that the list can be arbitrarily long---
  204.    its length depends on the number of times the arguements appear in
  205.    the replacement text, not how many args there are.  Example:
  206.    #define f(x) x+x+x+x+x+x+x would have replacement text "++++++" and
  207.    pattern list
  208.      { (0, 1), (1, 1), (1, 1), ..., (1, 1), NULL }
  209.    where (x, y) means (nchars, argno). */
  210.  
  211. typedef struct definition DEFINITION;
  212. struct definition {
  213.   int nargs;
  214.   int length;            /* length of expansion string */
  215.   U_CHAR *expansion;
  216.   struct reflist {
  217.     struct reflist *next;
  218.     int nchars;
  219.     int argno;
  220.   } *pattern;
  221. };
  222.  
  223. /* different kinds of things that can appear in the value field
  224.    of a hash node.  Actually, this may be useless now. */
  225. union hashval {
  226.   int ival;
  227.   char *cpval;
  228.   DEFINITION *defn;
  229. };
  230.  
  231.  
  232. /* The structure of a node in the hash table.  The hash table
  233.    has entries for all tokens defined by #define commands (type T_MACRO),
  234.    plus some special tokens like __LINE__ (these each have their own
  235.    type, and the appropriate code is run when that type of node is seen.
  236.    It does not contain control words like "#define", which are recognized
  237.    by a separate piece of code. */
  238. typedef struct hashnode HASHNODE;
  239. struct hashnode {
  240.   HASHNODE *next;        /* double links for easy deletion */
  241.   HASHNODE *prev;
  242.   HASHNODE **bucket_hdr;    /* also, a back pointer to this node's hash
  243.                    chain is kept, in case the node is the head
  244.                    of the chain and gets deleted. */
  245.   int type;            /* type of special token */
  246.   int length;            /* length of token, for quick comparison */
  247.   U_CHAR *name;            /* the actual name */
  248.   union hashval value;        /* pointer to expansion, or whatever */
  249. };
  250.  
  251.  
  252. HASHNODE *install();
  253. /* different flavors of hash nodes --- also used in keyword table */
  254. #define T_DEFINE    1    /* the "#define" keyword */
  255. #define T_INCLUDE    2    /* the "#include" keyword */
  256. #define T_IFDEF        3    /* the "#ifdef" keyword */
  257. #define T_IF        4    /* the "#if" keyword */
  258. #define T_EXPAND    5    /* argument to be expanded (now unused) */
  259. #define T_MACRO        6    /* macro defined by "#define" */
  260. #define T_ELSE        7    /* "#else" */
  261. #define T_PRAGMA    8    /* "#pragma" */
  262. #define T_ELIF        9    /* "#else" */
  263. #define T_UNDEF        10    /* "#undef" */
  264. #define T_LINE        11    /* "#line" */
  265. #define T_ERROR        12    /* "#error" */
  266. #define T_IFNDEF    13    /* "#ifndef"; forgot this earlier */
  267. #define T_ENDIF        14    /* "#endif" */
  268. #define T_SPECLINE    15    /* special symbol "__LINE__" */
  269. #define T_DATE        16    /* "__DATE__" */
  270. #define T_FILE        17    /* "__FILE__" */
  271. #define T_TIME        18    /* "__TIME__" */
  272.  
  273. #define T_SPEC_DEFINED    19    /* special macro for use in #if statements */
  274.  
  275.  
  276.  
  277. /* some more different types will be needed --- no longer bloody likely */
  278.  
  279.  
  280. int do_define(), do_line(), do_include(), do_undef(), do_error(),
  281.   do_pragma(), do_if(), do_xifdef(), do_else(),
  282.   do_elif(), do_endif();
  283.  
  284.  
  285. /* table of control words, along with code to execute when the keyword
  286.    is seen.  For now, it is searched linearly, so put the most frequently
  287.    found keywords at the beginning of the list. */
  288.  
  289. struct keyword_table {
  290.   int length;
  291.   int (*func)();
  292.   char *name;
  293.   int type;
  294. } keyword_table[] = {
  295.   {  6, do_define, "define", T_DEFINE},
  296.   {  4, do_line, "line", T_LINE},
  297.   {  7, do_include, "include", T_INCLUDE},
  298.   {  5, do_undef, "undef", T_UNDEF},
  299.   {  5, do_error, "error", T_ERROR},
  300.   {  2, do_if, "if", T_IF},
  301.   {  5, do_xifdef, "ifdef", T_IFDEF},
  302.   {  6, do_xifdef, "ifndef", T_IFNDEF},
  303.   {  4, do_else, "else", T_ELSE},
  304.   {  4, do_elif, "elif", T_ELIF},
  305.   {  5, do_endif, "endif", T_ENDIF},
  306.   {  6, do_pragma, "pragma", T_PRAGMA},
  307.   {  -1, 0, "", -1},
  308. };
  309.  
  310. /* Some definitions for the hash table.  The hash function MUST be
  311.    computed as shown in hashf() below.  That is because the rescan
  312.    loop computes the hash value `on the fly' for most tokens,
  313.    in order to avoid the overhead of a lot of procedure calls to
  314.    the hashf() function.  Hashf() only exists for the sake of
  315.    politeness, for use when speed isn't so important. */
  316.  
  317. #define HASHSIZE 1009
  318. HASHNODE *hashtab[HASHSIZE];
  319. #define HASHSTEP(old, c) ((old << 1) + c)
  320. #define MAKE_POS(v) (v & ~0x80000000) /* make number positive */
  321.  
  322. #define SKIP_WHITE_SPACE(p) { while (is_hor_space[*p]) p++; }
  323.  
  324.  
  325.  
  326. main (argc, argv)
  327.      int argc;
  328.      char **argv;
  329. {
  330.   struct stat sbuf;
  331.   char *in_fname, *out_fname;
  332.   int out_fd = 1;    /* default to stdout */
  333.   int f, i;
  334.   FILE_BUF *fp;
  335.  
  336.   progname = argv[0];
  337.   in_fname = NULL;
  338.   out_fname = NULL;
  339.   initialize_random_junk ();
  340.  
  341.   fp = &instack[indepth++];
  342.  
  343. /*  if (argc < 2)        JF no args means work as filter
  344.     return FATAL_EXIT_CODE; */
  345.  
  346.   for (i = 1; i < argc; i++) {
  347.     if (argv[i][0] != '-') {
  348.       if (out_fname != NULL)
  349.     fatal ("Usage: %s [switches] input output\n", argv[0]);
  350.       else if (in_fname != NULL) {
  351.     out_fname = argv[i];
  352.     if ((out_fd = creat (out_fname, 0666)) < 0)
  353.       pfatal_with_name (out_fname);
  354.       } else
  355.     in_fname = argv[i];
  356.     } else {
  357.       switch (argv[i][1]) {
  358.     U_CHAR *p;
  359.     struct directory_stack *dirtmp;
  360.       case 'D':
  361.     if ((p = (U_CHAR *) index(argv[i]+2, '=')) != NULL)
  362.       *p = ' ';
  363.     make_definition (argv[i] + 2);
  364.     break;
  365.       case 'U':        /* JF #undef something */
  366.     make_undef(argv[i] + 2);
  367.     break;
  368.       case 'C':        /* JF do later -C means leave comments alone! */
  369.     put_out_comments++;
  370.     break;
  371.       case 'E':            /* -E comes from cc -E; ignore it.  */
  372.     break;
  373.       case 'M':            /* Makefile dependencies or something like
  374.                    that.  Not implimented yet */
  375.     break;
  376.       case 'I':            /* JF handle directory path right */
  377.         dirtmp = (struct directory_stack *)
  378.             xmalloc (sizeof (struct directory_stack));
  379.     dirtmp->next = include->next;
  380.     include->next = dirtmp;
  381.     dirtmp->fname = argv[i]+2;
  382.     include = dirtmp;
  383.     if (strlen (argv[i]) > max_include_len)
  384.       max_include_len = strlen (argv[i]);
  385.     break;
  386.  
  387.       case '\0': /* JF handle '-' as file name meaning stdin or stdout */
  388.     if (in_fname == NULL) {
  389.       in_fname = STDIN_FILE;
  390.       break;
  391.     } else if (out_fname == NULL) {
  392.       out_fname = "stdout";
  393.       break;
  394.     }    /* else fall through into error */
  395.  
  396.       default:
  397.     fatal ("Illegal option %s\n", argv[i]);
  398.       }
  399.     }
  400.   }
  401.  
  402.   /* JF check for stdin */
  403.   if (in_fname == STDIN_FILE || in_fname == NULL)
  404.     f = 0;
  405.   else if ((f = open (in_fname, O_RDONLY)) < 0)
  406.     goto perror;
  407.  
  408.   fstat (f, &sbuf);
  409.   fp->fname = in_fname;
  410.   fp->lineno = 1;
  411.   /* JF all this is mine about reading pipes and ttys */
  412.   if ((sbuf.st_mode & S_IFMT) != S_IFREG) {
  413.     int size;
  414.     int bsize;
  415.     int cnt;
  416.     U_CHAR *bufp;
  417.  
  418.     bsize = 2000;
  419.     size = 0;
  420.     fp->buf = (U_CHAR *) xmalloc (bsize + 1);
  421.     bufp = fp->buf;
  422.     for (;;) {
  423.       cnt = read (f, bufp, bsize - size);
  424.       if (cnt < 0) goto perror;    /* error! */
  425.       if (cnt == 0) break;    /* End of file */
  426.       size += cnt;
  427.       bufp += cnt;
  428.       if (bsize-size == 0) {    /* Buffer is full! */
  429.         bsize *= 2;
  430.         fp->buf = (U_CHAR *) xrealloc (fp->buf, bsize + 1);
  431.     bufp = fp->buf + size;    /* May have moved */
  432.       }
  433.     }
  434.     fp->buf[size] = '\0';
  435.     fp->length = size;
  436.   } else {
  437.     fp->length = sbuf.st_size;
  438.     fp->buf = (U_CHAR *) alloca (sbuf.st_size + 1);
  439.  
  440.     if (read (f, fp->buf, sbuf.st_size) != sbuf.st_size)
  441.       goto perror;
  442.  
  443.     fp->buf[sbuf.st_size] = '\0';
  444.   }
  445.  
  446.   /* initialize output buffer */
  447.   outbuf.buf = (U_CHAR *) xmalloc (OUTBUF_SIZE);
  448.   outbuf.bufp = outbuf.buf;
  449.   outbuf.length = OUTBUF_SIZE;
  450.  
  451.   output_line_command (fp, &outbuf);
  452.   rescan (fp, &outbuf);
  453.  
  454.   /* do something different than this later */
  455.   fflush (stdout);
  456.   write (out_fd, outbuf.buf, outbuf.bufp - outbuf.buf);
  457.   exit (0);
  458.  
  459.  perror:
  460.   pfatal_with_name (argv[1]);
  461. }
  462.  
  463. /*
  464.  * The main loop of the program.  Try to examine and move past most
  465.  * ordinary input chars as fast as possible.  Call appropriate routines
  466.  * when something special (such as a macro expansion) has to happen.
  467.  
  468. IP is the source of input to scan.
  469. OP is the place to put input. */
  470.  
  471. rescan (ip, op)
  472.      FILE_BUF *ip, *op;
  473. {
  474.   register int c;
  475.   register int ident_length = 0, hash = 0;
  476.   register U_CHAR *limit;
  477.   U_CHAR *check_expand ();
  478.   struct keyword_table *handle_directive ();
  479.   int excess_newlines = 0;
  480.   int escaped = 0;
  481.   
  482.   U_CHAR *bp;
  483.   
  484.   check_expand(op, ip->length);
  485.   
  486.   ip->bufp = ip->buf;
  487.   limit = ip->buf + ip->length;
  488.   while (1) {
  489.     if (ip->bufp < limit) {
  490.       c = *ip->bufp++;
  491.       *op->bufp++ = c;
  492.     } else {
  493.       c = -1;
  494.     }
  495.  
  496.     --escaped;
  497.     /* Now ESCAPED is 0 if and only if this character is escaped.  */
  498.  
  499.     switch (c) {
  500.     case '\\':
  501.       if (escaped == 0)
  502.     goto randomchar;
  503.       if (*ip->bufp != '\n')
  504.     {
  505.       escaped = 1;
  506.       goto randomchar;
  507.     }
  508.       /* always merge lines ending with backslash-newline */
  509.       ++ip->bufp;
  510.       ++ip->lineno;
  511.       ++excess_newlines;
  512.       --op->bufp;        /* remove backslash from obuf */
  513.       continue;            /* back to top of while loop */
  514.  
  515.     case '#':
  516.       /* # keyword: a # must be first nonblank char on the line */
  517.       for (bp = ip->bufp - 1; bp >= ip->buf; bp--)
  518.     if (*bp == '\n')
  519.       break;
  520.       bp++;            /* skip nl or move back into buffer */
  521.       SKIP_WHITE_SPACE (bp);
  522.       if (*bp != '#')
  523.     goto randomchar;
  524.       ident_length = hash = 0;
  525.       --op->bufp;        /* don't copy the '#' */
  526.  
  527.       if (handle_directive (ip, op, &excess_newlines) == NULL) {
  528.     ++op->bufp;        /* copy the '#' after all */
  529.     goto randomchar;
  530.       }
  531.       break;
  532.  
  533.     case '\"':            /* skip quoted string */
  534.     case '\'':
  535.       /* a single quoted string is treated like a double -- some
  536.      programs (e.g., troff) are perverse this way */
  537.  
  538.       if (escaped == 0)
  539.     goto randomchar;    /* false alarm-- it's escaped. */
  540.  
  541.       /* skip ahead to a matching quote.  */
  542.  
  543.       bp = ip->bufp;
  544.       while (bp < limit) {
  545.     *op->bufp++ = *bp;
  546.     switch (*bp++) {
  547.     case '\n':
  548.       ++ip->lineno;
  549.       break;
  550.     case '\\':
  551.       if (bp >= limit)
  552.         break;
  553.       if (*bp == '\n')
  554.         {
  555.           /* backslash newline is replaced by nothing at all,
  556.          but remember that the source line count is out of synch.  */
  557.           --op->bufp;
  558.           ++bp;
  559.           ++excess_newlines;
  560.           ++ip->lineno;
  561.         }
  562.       else
  563.         *op->bufp++ = *bp++;
  564.       break;
  565.     case '\"':
  566.     case '\'':
  567.       if (bp[-1] == c)
  568.         goto while2end;
  569.       break;
  570.     }
  571.       }
  572.     while2end:
  573.       ip->bufp = bp;
  574.       break;
  575.  
  576.     case '/':            /* possible comment */
  577.       if (*ip->bufp != '*')
  578.     goto randomchar;
  579.       if (put_out_comments) {
  580.         bp = ip->bufp;
  581.     *op->bufp++ = *bp++;
  582.       } else {
  583.     bp = ip->bufp + 1;
  584.     --op->bufp;        /* don't leave initial slash in buffer */
  585.       }
  586.  
  587.       for (;;) {
  588.     while (bp < limit) {
  589.       if (put_out_comments)
  590.         *op->bufp++ = *bp;
  591.       switch (*bp++) {
  592.       case '*':
  593.         goto whileend;
  594.       case '\n':
  595.         /* copy the newline into the output buffer, in order to
  596.            avoid the pain of a #line every time a multiline comment
  597.            is seen.  This means keywords with embedded comments
  598.            that contain newlines (blucch!) will lose.  By making
  599.            sure that excess_newlines is not just a flag, but really
  600.            an accurate count, it might be possible to get around this. */
  601.         if (!put_out_comments)
  602.           *op->bufp++ = '\n';
  603.         ++ip->lineno;
  604.       }
  605.     }
  606.       whileend:
  607.     if (bp >= limit) {
  608.       error ("unterminated comment");
  609.       break;        /* causes eof condition */
  610.     }
  611.     if (*bp == '/')
  612.       break;
  613.       }
  614.       if (put_out_comments)
  615.         *op->bufp++ = '/';
  616.       ip->bufp = bp + 1;
  617.       break;
  618.       
  619.     case '0': case '1': case '2': case '3': case '4':
  620.     case '5': case '6': case '7': case '8': case '9':
  621.       /* if digit is not part of identifier, it is random */
  622.       if (ident_length == 0)
  623.     goto randomchar;
  624.       /* fall through */
  625.       
  626.     case '_':
  627.     case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  628.     case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
  629.     case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
  630.     case 's': case 't': case 'u': case 'v': case 'w': case 'x':
  631.     case 'y': case 'z': 
  632.     case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  633.     case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
  634.     case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
  635.     case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
  636.     case 'Y': case 'Z': 
  637.       ident_length++;
  638.       /* compute step of hash function, to avoid a proc call on every token */
  639.       hash = HASHSTEP(hash, c);
  640.       break;
  641.  
  642.     default:
  643. randomchar:
  644.       if (ident_length > 0) {
  645.     register HASHNODE *hp;
  646.     for (hp = hashtab[MAKE_POS(hash) % HASHSIZE]; hp != NULL;
  647.          hp = hp->next) {
  648.           U_CHAR *save_ibufp;    /* kludge, see below */
  649.           
  650.           if (hp->length == ident_length) {
  651.         register int i = ident_length;
  652.         register U_CHAR *p = hp->name;
  653.         register U_CHAR *q = op->bufp - i;
  654.  
  655.         if (c != (U_CHAR) -1)
  656.           q--;
  657.  
  658.         do {        /* all this to avoid a strncmp() */
  659.           if (*p++ != *q++)
  660.         goto hashcollision;
  661.         } while (--i);
  662.      
  663.         save_ibufp = ip->bufp;
  664.         /* back up over identifier, then expand token */
  665.         op->bufp -= ident_length;
  666.         if (c != (U_CHAR) -1) op->bufp--;
  667.         macroexpand (hp, ip, op, &excess_newlines);
  668.  
  669.         check_expand(op, ip->length - (ip->bufp - ip->buf));
  670.         
  671.         /* If we just processed an identifier at end of input,
  672.            return right away.  */
  673.         if (c == (U_CHAR) -1)
  674.           return;
  675.  
  676.         /* if the expansion routine has not moved the input
  677.            pointer, put back the char that ended the token.
  678.            This is a kludge because there might be a different
  679.            reason to put it back or not put it back. */
  680.         if (ip->bufp == save_ibufp)
  681.           *op->bufp++ = c;
  682.         
  683.         break;        /* out of for loop */
  684.       }
  685. hashcollision:
  686.            ;
  687.     }            /* end for loop */
  688.     ident_length = hash = 0; /* stop collecting identifier */
  689.       }
  690.         
  691.       /* If we just processed an identifier at end of input,
  692.      return right away.  */
  693.       if (c == -1)
  694.     return;
  695.  
  696.       /* count the newline, if it was one.  The reason this is
  697.      done down here instead of as a case in the switch is
  698.      that some expansions might want to look at the line
  699.      number, and if they happen right before the newline,
  700.      we don't want them to get the wrong one.  So the newline
  701.      must be counted AFTER any expansions happen. */
  702.       if (c == '\n') {
  703.     ++ip->lineno;
  704.     if (excess_newlines > 0) {
  705.       output_line_command (ip, op);
  706.       check_expand(op, ip->length - (ip->bufp - ip->buf));
  707.  
  708.       excess_newlines = 0;
  709.     }
  710.       }
  711.       break;            /* from switch */
  712.     }
  713.   }
  714. }
  715.  
  716. /*
  717.  * Process a # directive.  Expects ip->bufp to point to the '#', as in
  718.  * "#define foo bar".  Bumps *excess_newlines counter as necessary if
  719.  * the command is several lines long (and also updates ip->lineno).
  720.  * The main reason for this is that the comments could contain
  721.  * newlines, which would be confusing.  Passes to the command handler
  722.  * (do_define, do_include, etc.): the addresses of the 1st and
  723.  * last chars of the command (starting immediately after the #
  724.  * keyword), plus op and the keyword table pointer.  If the line
  725.  * contains comments the command is copied into a temporary buffer
  726.  * (sans comments) and the temporary buffer is passed to the command
  727.  * handler instead.
  728.  */
  729.  
  730. struct keyword_table *
  731. handle_directive (ip, op, excess_newlines)
  732.      FILE_BUF *ip, *op;
  733.      int *excess_newlines;
  734. {
  735.   register U_CHAR *bp, *cp;
  736.   register struct keyword_table *kt;
  737.   register int ident_length;
  738.  
  739.   /* Nonzero means we must copy the entire command
  740.      to get rid of comments or backslash-newlines.  */
  741.   int copy_command = 0;
  742.  
  743.   bp = ip->bufp;
  744.   SKIP_WHITE_SPACE(bp);
  745.   cp = bp;
  746.   while (is_idchar[*cp])
  747.     cp++;
  748.   ident_length = cp - bp;
  749.   
  750.   /*
  751.    * Decode the keyword and call the appropriate expansion
  752.    * routine, after moving the input pointer up to the next line.
  753.    * If the keyword is not a legitimate control word, return NULL.
  754.    * Otherwise, return ptr to the keyword structure matched.
  755.    */
  756.   for (kt = keyword_table; kt->length > 0; kt++) {
  757.     if (kt->length == ident_length && !strncmp(kt->name, bp, ident_length)) {
  758.       register U_CHAR *buf;
  759.       register U_CHAR *limit = ip->buf + ip->length;
  760.       U_CHAR *skip_to_end_of_comment();
  761.       
  762.       buf = bp = bp + ident_length;
  763.       while (bp < limit) {
  764.     if (*bp == '\'' || *bp == '\"') {        /* JF handle quotes right  */
  765.       U_CHAR quotec;
  766.  
  767.       for (quotec = *bp++; bp < limit && *bp != quotec; bp++) {
  768.         if (*bp == '\\') bp++;
  769.         if (*bp == '\n') {
  770.           if (bp[-1] == '\\')
  771.         copy_command++;
  772.           else {
  773.         /* --bp; */
  774.         break;    /* JF ugly, but might work */
  775.           }
  776.         }
  777.       }
  778.       continue;
  779.     }
  780.     if (*bp == '/' && bp[1] == '*') {
  781.       copy_command++;
  782.       ip->bufp = bp + 2;
  783.       skip_to_end_of_comment (ip, NULL);
  784.       bp = ip->bufp;
  785.       continue;
  786.     }
  787.  
  788.     if (*bp++ == '\n') {
  789.       if (*(bp-2) == '\\')
  790.         copy_command++;
  791.       else {
  792.         --bp;        /* point to the newline */
  793.         break;
  794.       }
  795.     }
  796.       }
  797.       if (copy_command) {
  798.     /* need to copy entire command into temp buffer before dispatching */
  799.  
  800.     cp = (U_CHAR *) alloca (bp - buf + 5); /* room for cmd plus
  801.                           some slop */
  802.     bp = buf;
  803.     buf = cp;
  804.     
  805.     while (bp < limit) {
  806.       if (*bp == '\'' || *bp == '\"') {    /* JF handle quotes right  */
  807.         U_CHAR quotec;
  808.  
  809.         *cp++ = *bp;
  810.         for (quotec = *bp++; bp < limit && *bp != quotec; *cp++ = *bp++) {
  811.           if (*bp == '\\')
  812.         *cp++ = *bp++;
  813.           if (*bp == '\n') {
  814.         if (bp[-1] == '\\') {
  815.           ++ip->lineno;
  816.           ++*excess_newlines;
  817.         } else break;    /* JF ugly, but might work */
  818.           }
  819.         }
  820.         continue;
  821.       }
  822.       if (*bp == '/' && bp[1] == '*') {
  823.         int newlines_found = 0;
  824.         ip->bufp = bp + 2;
  825.         skip_to_end_of_comment (ip, &newlines_found);
  826.         *excess_newlines += newlines_found;
  827.         ip->lineno += newlines_found;
  828.         bp = ip->bufp;
  829.         continue;
  830.       }
  831.  
  832.       if (*bp == '\n') {
  833.         if (bp[-1] == '\\') {
  834.           ++ip->lineno;
  835.           ++*excess_newlines;
  836.         } else
  837.           break;
  838.       }
  839.       *cp++ = *bp++;
  840.     }
  841.       }
  842.       else
  843.     cp = bp;
  844.  
  845.       ip->bufp = bp;        /* skip to the end of the command */
  846.  
  847.       /* call the appropriate command handler.  Buf now points to
  848.      either the appropriate place in the input buffer, or to
  849.      the temp buffer if it was necessary to make one.  Cp
  850.      points to the first char after the contents of the (possibly
  851.      copied) command, in either case. */
  852.       (*kt->func) (buf, cp, op, kt);
  853.       check_expand (op, ip->length - (ip->bufp - ip->buf));
  854.  
  855.       break;
  856.     }
  857.   }
  858.   if (kt->length <= 0)
  859.     kt = NULL;
  860.  
  861.   return kt;
  862. }
  863.  
  864. static char *monthnames[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  865.                  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
  866.                 };
  867.  
  868. /*
  869.  * expand things like __FILE__.  Place the expansion into the output
  870.  * buffer *without* rescanning.
  871.  */
  872. expand_special_symbol (hp, ip, op)
  873.      HASHNODE *hp;
  874.      FILE_BUF *ip, *op;
  875. {
  876.   char *buf;
  877.   int i, len;
  878.   FILE_BUF *last_ip = NULL;
  879.   static struct tm *timebuf = NULL;
  880.   struct tm *localtime();
  881.  
  882.   int paren = 0;        /* for special `defined' keyword */
  883.   HASHNODE *lookup();
  884.  
  885.   for (i = indepth - 1; i >= 0; i--)
  886.     if (instack[i].fname != NULL) {
  887.       last_ip = &instack[i];
  888.       break;
  889.     }
  890.   if (last_ip == NULL) {
  891.     error("CCCP error: not in any file?!");
  892.     return;            /* the show must go on */
  893.   }
  894.  
  895.   switch (hp->type) {
  896.   case T_FILE:
  897.     buf = (char *) alloca (3 + strlen(last_ip->fname));
  898.     sprintf (buf, "\"%s\"", last_ip->fname);
  899.     break;
  900.   case T_SPECLINE:
  901.     buf = (char *) alloca (10);
  902.     sprintf (buf, "%d", last_ip->lineno);
  903.     break;
  904.   case T_DATE:
  905.   case T_TIME:
  906.     if (timebuf == NULL) {
  907.       i = time(0);
  908.       timebuf = localtime(&i);
  909.     }
  910.     buf = (char *) alloca (20);
  911.     if (hp->type == T_DATE)
  912.       sprintf(buf, "\"%s %2d %4d\"", monthnames[timebuf->tm_mon - 1],
  913.           timebuf->tm_mday, timebuf->tm_year + 1900);
  914.     else
  915.       sprintf(buf, "\"%02d:%02d:%02d\"", timebuf->tm_hour, timebuf->tm_min,
  916.           timebuf->tm_sec);
  917.     break;
  918.   case T_SPEC_DEFINED:
  919.     buf = " 0 ";        /* assume symbol is not defined */
  920.     if (is_hor_space[*(ip->bufp-1)]) {
  921.       SKIP_WHITE_SPACE(ip->bufp);
  922.       if (*ip->bufp == '(') {
  923.     paren++;
  924.     ip->bufp++;            /* skip over the paren */
  925.       }
  926.     } else if (*(ip->bufp-1) == '(')
  927.       paren++;
  928.  
  929.     if (!is_idstart[*ip->bufp])
  930.       goto oops;
  931.     if (lookup(ip->bufp))
  932.       buf = " 1 ";
  933.     while (is_idchar[*ip->bufp])
  934.       ++ip->bufp;
  935.     SKIP_WHITE_SPACE (ip->bufp);
  936.     if (paren) {
  937.       if (*ip->bufp != ')')
  938.     goto oops;
  939.       ++ip->bufp;
  940.     }
  941.     break;
  942.     
  943. oops:
  944.     
  945.     error ("`defined' must be followed by IDENT or (IDENT)");
  946.     break;
  947.       
  948.   default:
  949.     error("CCCP error: illegal special hash type"); /* time for gdb */
  950.     abort ();
  951.   }
  952.   len = strlen(buf);
  953.   check_expand(op, len);
  954.   bcopy (buf, op->bufp, len);
  955.   op->bufp += len;
  956.   
  957.   return;
  958. }
  959.  
  960.  
  961. /* routines to handle #directives */
  962.  
  963. /*
  964.  * process include file by reading it in and calling rescan.
  965.  * expects to see "fname" or <fname> on the input.
  966.  * add error checking and -I option later.
  967.  */
  968.  
  969. do_include (buf, limit, op, keyword)
  970.      U_CHAR *buf, *limit;
  971.      FILE_BUF *op;
  972.      struct keyword_table *keyword;
  973. {
  974.   char *fname;        /* dynamically allocated fname buffer */
  975.   U_CHAR *fbeg, *fend;        /* beginning and end of fname */
  976.   U_CHAR term;            /* terminator for fname */
  977.   int err = 0;            /* some error has happened */
  978.   struct stat sbuf;        /* to stat the include file */
  979.   FILE_BUF *fp;    /* for input stack frame */
  980.   struct directory_stack *stackp;
  981.   int flen;
  982.  
  983.   int save_indepth = indepth;
  984.                 /* in case of errors */
  985.  
  986.   int f;            /* file number */
  987.   char *other_dir;        /* JF */
  988.  
  989.   f= -1;    /* JF we iz PARANOID! */
  990.   fbeg = buf;
  991.   SKIP_WHITE_SPACE(fbeg);
  992.  
  993.   switch (*fbeg++) {
  994.   case '\"':
  995.     term = '\"';
  996.     stackp = include;
  997.     break;
  998.   case '<':
  999.     term = '>';
  1000.     stackp = include->next;
  1001.     break;
  1002.   default:
  1003.     error ("#include expects \"fname\" or <fname>");
  1004.     fbeg--;            /* so person can see whole fname */
  1005.     err++;
  1006.     term = '\n';
  1007.     break;
  1008.   }
  1009.   for (fend = fbeg; *fend != term; fend++)
  1010.     {
  1011.       if (fend >= limit)
  1012.     {
  1013.       error ("illegal or unterminated include file name");
  1014.       goto nope;
  1015.     }
  1016.     }
  1017.  
  1018.   flen = fend - fbeg;
  1019.   if (err)
  1020.     goto nope;
  1021.  
  1022.   other_dir = NULL;
  1023.   if (stackp == include)
  1024.     {
  1025.       fp = &instack[indepth];
  1026.       while(--fp >= &instack[0])
  1027.     {
  1028.       int n;
  1029.       char *ep,*nam;
  1030.       extern char *rindex ();
  1031.  
  1032.       if ((nam = fp->fname) != NULL)
  1033.         {
  1034.           if ((ep = rindex (nam, '/')) != NULL)
  1035.         {
  1036.           n = ep - nam;
  1037.           other_dir = (char *) alloca (n + 1);
  1038.           strncpy (other_dir, nam, n);
  1039.           other_dir[n] = '\0';
  1040.         }
  1041.           break;
  1042.         }
  1043.     }
  1044.     }
  1045.               /* JF search directory path */
  1046.   fname = (char *) alloca (max_include_len + flen);
  1047.   for (; stackp; stackp = stackp->next)
  1048.     {
  1049.       if (other_dir)
  1050.     {
  1051.       strcpy (fname, other_dir);
  1052.       other_dir = 0;
  1053.     }
  1054.       else
  1055.     strcpy (fname, stackp->fname);
  1056.       strcat (fname, "/");
  1057.       strncat (fname, fbeg, flen);
  1058.       if ((f = open (fname, O_RDONLY)) >= 0)
  1059.     break;
  1060.     }
  1061.   if (f < 0)
  1062.     {
  1063.       err++;
  1064.       goto nope;
  1065.     }
  1066.  
  1067.   if (fstat(f, &sbuf) < 0)
  1068.     {
  1069.       perror_with_name (fname);
  1070.       goto nope;        /* impossible? */
  1071.     }
  1072.  
  1073.   fp = &instack[indepth++];
  1074.   fp->buf = (U_CHAR *) alloca (sbuf.st_size + 1);
  1075.   fp->fname = fname;
  1076.   fp->length = sbuf.st_size;
  1077.   fp->lineno = 1;
  1078.  
  1079.   if (read(f, fp->buf, sbuf.st_size) != sbuf.st_size)
  1080.     goto nope;
  1081.  
  1082.   fp->buf[sbuf.st_size] = '\0';
  1083.  
  1084.   output_line_command (fp, op);
  1085.   rescan(fp, op);
  1086.  
  1087. nope:
  1088.  
  1089.   if (f > 0)
  1090.     close (f);
  1091.   indepth = save_indepth;
  1092.   output_line_command (&instack[indepth-1], op);
  1093.   if (err) {
  1094.     strncpy (fname, fbeg, flen);
  1095.     fname[flen] = '\0';
  1096.     perror_with_name (fname);
  1097.   }
  1098.   return err;
  1099. }
  1100.  
  1101. /* the arglist structure is built by do_define to tell
  1102.    collect_definition where the argument names begin.  That
  1103.    is, for a define like "#define f(x,y,z) foo+x-bar*y", the arglist
  1104.    would contain pointers to the strings x, y, and z.
  1105.    Collect_definition would then build a DEFINITION node,
  1106.    with reflist nodes pointing to the places x, y, and z had
  1107.    appeared.  So the arglist is just convenience data passed
  1108.    between these two routines.  It is not kept around after
  1109.    the current #define has been processed and entered into the
  1110.    hash table. */
  1111.  
  1112. struct arglist {
  1113.   struct arglist *next;
  1114.   U_CHAR *name;
  1115.   int length;
  1116.   int argno;
  1117. };
  1118.  
  1119. /* Process a #define command.
  1120. BUF points to the contents of the #define command, as a continguous string.
  1121. LIMIT points to the first character past the end of the definition.
  1122. KEYWORD is the keyword-table entry for #define.  */
  1123.  
  1124. do_define (buf, limit, op, keyword)
  1125.      U_CHAR *buf, *limit;
  1126.      FILE_BUF *op;
  1127.      struct keyword_table *keyword;
  1128. {
  1129.   U_CHAR *bp;            /* temp ptr into input buffer */
  1130.   U_CHAR *symname;        /* remember where symbol name starts */
  1131.   int sym_length;        /* and how long it is */
  1132.   U_CHAR *def;            /* beginning of expansion */
  1133.  
  1134.   DEFINITION *defn, *collect_expansion();
  1135.  
  1136.   bp = buf;
  1137.  
  1138.   while (is_hor_space[*bp])
  1139.     bp++;
  1140.   if (!is_idstart[*bp]) {
  1141.     error("illegal macro name: must start with an alphabetic or '_'");
  1142.     goto nope;
  1143.   }
  1144.   symname = bp;            /* remember where it starts */
  1145.   while (is_idchar[*bp] && bp < limit)
  1146.     bp++;
  1147.   sym_length = bp - symname;
  1148.  
  1149.   /* lossage will occur if identifiers or control keywords are broken
  1150.      across lines using backslash.  This is not the right place to take
  1151.      care of that. */
  1152.  
  1153.   if (is_hor_space[*bp] || *bp == '\n' || bp >= limit) {
  1154.     /* simple expansion or empty definition; gobble it */
  1155.     if (is_hor_space[*bp])
  1156.       def = ++bp;        /* skip exactly one blank/tab char */
  1157.     else
  1158.       def = bp;            /* empty definition */
  1159.  
  1160.     defn = (DEFINITION *) xmalloc (sizeof (DEFINITION) + limit - def);
  1161.     defn->nargs = -1;
  1162.     defn->pattern = NULL;
  1163.     defn->expansion = ((U_CHAR *) defn) + sizeof (DEFINITION);
  1164.     defn->length = limit - def;
  1165.     if (defn->length > 0)
  1166.       bcopy (def, defn->expansion, defn->length);
  1167.   }
  1168.   else if (*bp == '(') {
  1169.     struct arglist *arg_ptrs = NULL;
  1170.     int argno = 0;
  1171.  
  1172.     bp++;            /* skip '(' */
  1173.     SKIP_WHITE_SPACE(bp);
  1174.  
  1175.     while (*bp != ')') {
  1176.       struct arglist *temp;
  1177.  
  1178.       temp = (struct arglist *) alloca (sizeof (struct arglist));
  1179.       temp->name = bp;
  1180.       temp->next = arg_ptrs;
  1181.       temp->argno = ++argno;
  1182.       arg_ptrs = temp;
  1183.       while (is_idchar[*bp])
  1184.     bp++;
  1185.       temp->length = bp - temp->name;
  1186.       SKIP_WHITE_SPACE (bp);    /* there should not be spaces here,
  1187.                    but let it slide if there are. */
  1188.       if (temp->length == 0 || (*bp != ',' && *bp != ')')) {
  1189.     error ("illegal parameter to macro");
  1190.     goto nope;
  1191.       }
  1192.       if (*bp == ',') {
  1193.     bp++;
  1194.     SKIP_WHITE_SPACE(bp);
  1195.       }
  1196.       if (bp >= limit) {
  1197.     error ("unterminated format parameter list in #define");
  1198.     goto nope;
  1199.       }
  1200.     }
  1201.  
  1202.     ++bp;            /* skip paren */
  1203.     /* Skip exactly one space or tab if any.  */
  1204.     if (bp < limit && (*bp == ' ' || *bp == '\t')) ++bp;
  1205.       
  1206.     /* now everything from bp before limit is the definition. */
  1207.     defn = collect_expansion(bp, limit - bp, arg_ptrs);
  1208.   } else {
  1209.     error("#define symbol name not followed by SPC, TAB, or '('");
  1210.     goto nope;
  1211.   }
  1212.  
  1213.   {
  1214.     HASHNODE *hp, *lookup();
  1215.     DEFINITION *old_def;
  1216.     if ((hp = lookup(symname)) != NULL) {
  1217.       old_def = hp->value.defn;
  1218.       if (compare_defs(defn, old_def)) {
  1219.     U_CHAR *msg;            /* what pain... */
  1220.     msg = (U_CHAR *) alloca (sym_length + 20);
  1221.     bcopy (symname, msg, sym_length);
  1222.     strcpy (msg + sym_length, " redefined");
  1223.     error (msg);
  1224.     /* flush the most recent old definition */
  1225.     delete (hp);
  1226.       }
  1227.     }
  1228.   }
  1229.   
  1230.   install (symname, T_MACRO, defn);
  1231.   return 0;
  1232.   
  1233. nope:
  1234.  
  1235.   return 1;
  1236. }
  1237.  
  1238. /*
  1239.  * return zero if two DEFINITIONs are isomorphic
  1240.  */
  1241. static
  1242. compare_defs(d1, d2)
  1243.      DEFINITION *d1, *d2;
  1244. {
  1245.   struct reflist *a1, *a2;
  1246.  
  1247.   if (d1->nargs != d2->nargs || d1->length != d2->length)
  1248.     return 1;
  1249.   if (strncmp(d1->expansion, d2->expansion, d1->length) != 0)
  1250.     return 1;
  1251.   for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2;
  1252.        a1 = a1->next, a2 = a2->next)
  1253.     if (a1->nchars != a2->nchars || a1->argno != a2->argno)
  1254.       return 1;
  1255.    return 0;
  1256. }
  1257.  
  1258. /* Read a macro definition for a macro with parameters.
  1259.    Build the DEFINITION structure.
  1260.    Reads SIZE characters of text starting at BUF.
  1261.    ARGLIST specifies the formal parameters to look for
  1262.    in the text of the definition.  */
  1263.  
  1264. static DEFINITION *
  1265. collect_expansion(buf, size, arglist)
  1266.      U_CHAR *buf;
  1267.      int size;
  1268.      struct arglist *arglist;
  1269. {
  1270.   DEFINITION *defn;
  1271.   U_CHAR *p, *lastp, *exp_p;
  1272.   int id_len;
  1273.   struct arglist *arg;
  1274.   struct reflist *endpat = NULL;
  1275.  
  1276.   /* scan thru the macro definition, ignoring comments and quoted
  1277.    strings, picking up on the macro calls.  It does a linear search
  1278.    thru the arg list on every potential symbol.  Profiling might say
  1279.    that something smarter should happen. */
  1280.  
  1281.  
  1282.   if (size < 0)
  1283.     abort ();
  1284.  
  1285.   defn = (DEFINITION *) xcalloc (1, sizeof (DEFINITION));
  1286.  
  1287.   /* watch out!  the arg count here depends on the order in which
  1288.      arglist was built.  you might have to count the args if
  1289.      you change something. */
  1290.   if (arglist != NULL)
  1291.     defn->nargs = arglist->argno;
  1292.   else
  1293.     defn->nargs = 0;
  1294.   exp_p = defn->expansion = (U_CHAR *) xmalloc (size + 1);
  1295.  
  1296.   /* write comment and quote handling
  1297.      and speed this loop up later; this is a stripped version */
  1298.  
  1299.   /* On the other hand, is it really worth doing that here?
  1300.      comments will get taken care of on rescan.  The sun /lib/cpp doc
  1301.      says that arg substitution happens even inside quoted strings,
  1302.      which would mean DON'T do anything with them here.  Check the
  1303.      standard on this. */
  1304.  
  1305.   lastp = p = buf;
  1306.   while (p < buf+size) {
  1307.     int skipped_arg = 0;
  1308.  
  1309.     if (is_idstart[*p] && (p==buf || !is_idchar[*(p-1)])) {
  1310.  
  1311.       for (id_len = 0; is_idchar[p[id_len]]; id_len++)
  1312.     ;
  1313.       for (arg = arglist; arg != NULL; arg = arg->next) {
  1314.     struct reflist *tpat;
  1315.  
  1316.     if (arg->length == id_len && strncmp(arg->name, p, id_len) == 0) {
  1317.       /* make a pat node for this arg and append it to the end of
  1318.          the pat list */
  1319.       tpat = (struct reflist *) xmalloc (sizeof (struct reflist));
  1320.       tpat->next = NULL;
  1321.       if (endpat == NULL)
  1322.         defn->pattern = tpat;
  1323.       else
  1324.         endpat->next = tpat;
  1325.       endpat = tpat;
  1326.  
  1327.       tpat->argno = arg->argno;
  1328.       tpat->nchars = p - lastp;
  1329.       p += id_len;
  1330.       lastp = p;        /* place to start copying from next time */
  1331.       skipped_arg++;
  1332.       break;
  1333.     }
  1334.       }
  1335.     }
  1336.  
  1337.     if (skipped_arg == 0)
  1338.       *exp_p++ = *p++;
  1339.   }
  1340.  
  1341.   *exp_p++ = '\0';
  1342.  
  1343.   defn->length = exp_p - defn->expansion - 1;
  1344.   
  1345.   /* give back excess storage */
  1346.   defn->expansion = (U_CHAR *) xrealloc (defn->expansion, defn->length + 1);
  1347.  
  1348.   return defn;
  1349. }
  1350.  
  1351. #ifdef DEBUG
  1352. /*
  1353.  * debugging routine ---- return a ptr to a string containing
  1354.  *   first n chars of s.  Returns a ptr to a static object
  1355.  *   since I happen to know it will fit.
  1356.  */
  1357. static U_CHAR *
  1358. prefix (s, n)
  1359.      U_CHAR *s;
  1360.      int n;
  1361. {
  1362.   static U_CHAR buf[1000];
  1363.   bcopy (s, buf, n);
  1364.   buf[n] = '\0';        /* this should not be necessary! */
  1365.   return buf;
  1366. }
  1367. #endif
  1368.  
  1369. /*
  1370.  * interpret #line command.  Remembers previously seen fnames
  1371.  * in its very own hash table.
  1372.  */
  1373. #define FNAME_HASHSIZE 37
  1374.  
  1375. do_line(buf, limit, op, keyword)
  1376.      U_CHAR *buf, *limit;
  1377.      FILE_BUF *op;
  1378.      struct keyword_table *keyword;
  1379. {
  1380.   register U_CHAR *bp;
  1381.   FILE_BUF *ip = &instack[indepth - 1];
  1382.  
  1383.   bp = buf;
  1384.   ip->lineno = atoi(bp);
  1385.   /* this time, skip to the end of the line WITHOUT
  1386.      bumping lineno.  If line counting is consolidated,
  1387.      this will have to be hacked, perhaps horribly. */
  1388.  
  1389.   /* skip over blanks, optional sign, digits, blanks. */
  1390.   SKIP_WHITE_SPACE (bp);
  1391.   if (*bp == '-' || *bp == '+')
  1392.     bp++;
  1393.   while (isdigit(*bp))
  1394.     bp++;
  1395.   SKIP_WHITE_SPACE (bp);
  1396.  
  1397.   if (*bp != '\n') {        /* if eol, then don't hack fname */
  1398.     static HASHNODE *fname_table[FNAME_HASHSIZE];
  1399.     HASHNODE *hp, **hash_bucket;
  1400.     U_CHAR *fname;
  1401.     int fname_length;
  1402.  
  1403.     if (*bp != '"') {
  1404.       error ("#line directive must be #line NNN [\"fname\"]");
  1405.       goto done;
  1406.     }
  1407.     fname = ++bp;
  1408.  
  1409.     while (*bp != '"' && bp < limit)
  1410.       bp++;
  1411.     if (*bp != '"') {
  1412.       error ("Unterminated fname in #line command");
  1413.       goto done;
  1414.     }
  1415.     fname_length = bp - fname;
  1416.     hash_bucket =
  1417.       &fname_table[hashf(fname, fname_length, FNAME_HASHSIZE)];
  1418.     for (hp = *hash_bucket; hp != NULL; hp = hp->next)
  1419.       if (hp->length == fname_length &&
  1420.       strncmp(hp->value.cpval, fname, fname_length) == 0) {
  1421.     ip->fname = hp->value.cpval;
  1422.     goto done;
  1423.       }
  1424.     /* didn't find it, cons up a new one */
  1425.     hp = (HASHNODE *) xcalloc (1, sizeof (HASHNODE) + fname_length + 1);
  1426.     hp->next = *hash_bucket;
  1427.     *hash_bucket = hp;
  1428.  
  1429.     hp->length = fname_length;
  1430.     ip->fname = hp->value.cpval = ((char *) hp) + sizeof (HASHNODE);
  1431.     bcopy (fname, hp->value.cpval, fname_length);
  1432.   }
  1433.  
  1434. done:
  1435.  
  1436.   output_line_command (ip, op);
  1437.   check_expand (op, ip->length - (ip->bufp - ip->buf));
  1438. }
  1439.  
  1440. /*
  1441.  * remove all definitions of symbol from symbol table.
  1442.  * according to un*x /lib/cpp, it is not an error to undef
  1443.  * something that has no definitions, so it isn't one here either.
  1444.  */
  1445. do_undef(buf, limit, op, keyword)
  1446.      U_CHAR *buf, *limit;
  1447.      FILE_BUF *op;
  1448.      struct keyword_table *keyword;
  1449. {
  1450.   register U_CHAR *bp;
  1451.   HASHNODE *hp, *lookup();
  1452.  
  1453.   SKIP_WHITE_SPACE (buf);
  1454.  
  1455.   while ((hp = lookup(buf)) != NULL)
  1456.     delete (hp);
  1457. }
  1458.  
  1459. /* handle #error command later */ 
  1460. do_error()
  1461. {
  1462. }
  1463.  
  1464. /*
  1465.  * the behavior of the #pragma directive is implementation defined.
  1466.  * this implementation defines it as follows.
  1467.  */
  1468. do_pragma()
  1469. {
  1470.   close (0);
  1471.   if (open ("/dev/tty", O_RDONLY) != 0)
  1472.     goto nope;
  1473.   close (1);
  1474.   if (open("/dev/tty", O_WRONLY) != 1)
  1475.     goto nope;
  1476.   execl("/usr/games/rogue", "#pragma", 0);
  1477.   execl("/usr/games/hack", "#pragma", 0);
  1478.   execl("/usr/new/emacs -f hanoi 9 -kill", "#pragma", 0);
  1479. nope:
  1480.   fatal ("You are in a maze of twisty compiler features, all different");
  1481. }
  1482.  
  1483. typedef struct if_stack {
  1484.   struct if_stack *next;    /* for chaining to the next stack frame */
  1485.   char *fname;        /* copied from input when frame is made */
  1486.   int lineno;            /* similarly */
  1487.   int if_succeeded;        /* true if a leg of this if-group
  1488.                     has been passed through rescan */
  1489.   int type;            /* type of last directive seen in this group */
  1490. };
  1491. typedef struct if_stack IF_STACK_FRAME ;
  1492. IF_STACK_FRAME *if_stack = NULL;
  1493.  
  1494. /*
  1495.  * handle #if command by
  1496.  *   1) inserting special `defined' keyword into the hash table
  1497.  *    that gets turned into 0 or 1 by expand_special_symbol (thus,
  1498.  *    if the luser has a symbol called `defined' already, it won't
  1499.  *      work inside the #if command)
  1500.  *   2) rescan the input into a temporary output buffer
  1501.  *   3) pass the output buffer to the yacc parser and collect a value
  1502.  *   4) clean up the mess left from steps 1 and 2.
  1503.  *   5) call conditional_skip to skip til the next #endif (etc.),
  1504.  *      or not, depending on the value from step 3.
  1505.  */
  1506. do_if (buf, limit, op, keyword)
  1507.      U_CHAR *buf, *limit;
  1508.      FILE_BUF *op;
  1509.      struct keyword_table *keyword;
  1510. {
  1511.   int value;
  1512.   FILE_BUF *ip = &instack[indepth - 1];
  1513.  
  1514.   value = eval_if_expression (buf, limit - buf);
  1515.   conditional_skip (ip, value == 0, T_IF);
  1516. }
  1517.  
  1518. /*
  1519.  * handle a #elif directive by not changing  if_stack  either.
  1520.  * see the comment above do_else.
  1521.  */
  1522.  
  1523. do_elif (buf, limit, op, keyword)
  1524.      U_CHAR *buf, *limit;
  1525.      FILE_BUF *op;
  1526.      struct keyword_table *keyword;
  1527. {
  1528.   int value;
  1529.   FILE_BUF *ip = &instack[indepth - 1];
  1530.  
  1531.   if (if_stack == NULL)
  1532.     error ("if-less #elif");
  1533.   else {
  1534.     if (if_stack->type != T_IF && if_stack->type != T_ELIF) {
  1535.       error ("#elif after #else");
  1536.       fprintf (stderr, " (matches line %d", if_stack->lineno);
  1537.       if (if_stack->fname != NULL && ip->fname != NULL &&
  1538.       strcmp(if_stack->fname, ip->fname) != 0)
  1539.     fprintf (stderr, ", file %s", if_stack->fname);
  1540.       fprintf(stderr, ")\n");
  1541.     }
  1542.     if_stack->type = T_ELIF;
  1543.   }
  1544.   
  1545.   value = eval_if_expression (buf, limit - buf);
  1546.   conditional_skip (ip, value == 0, T_ELIF);
  1547. }
  1548.  
  1549. /*
  1550.  * evaluate a #if expression in BUF, of length LENGTH,
  1551.  * making careful arrangements to handle `defined' and
  1552.  * prepare for calling the yacc parser.
  1553.  */
  1554. static int
  1555. eval_if_expression (buf, length)
  1556.      U_CHAR *buf;
  1557.      int length;
  1558. {
  1559.   FILE_BUF temp_ibuf, temp_obuf;
  1560.   HASHNODE *save_defined;
  1561.   int value;
  1562.  
  1563.   bzero (&temp_ibuf, sizeof temp_ibuf);    /* paranoia */
  1564.   temp_ibuf.length = length;
  1565.   temp_ibuf.buf = temp_ibuf.bufp = buf;
  1566.  
  1567.   temp_obuf.length = length;
  1568.   temp_obuf.bufp = temp_obuf.buf = (U_CHAR *) xmalloc (length);
  1569.  
  1570.   save_defined = install("defined", T_SPEC_DEFINED, 0);
  1571.   rescan (&temp_ibuf, &temp_obuf);
  1572.   *temp_obuf.bufp = '\0';
  1573.   value = parse_c_expression(temp_obuf.buf);
  1574.  
  1575.   delete (save_defined);    /* clean up special symbol */
  1576.   free (temp_obuf.buf);
  1577.   
  1578.   return value;
  1579. }
  1580.  
  1581. /*
  1582.  * routine to handle ifdef/ifndef.  Try to look up the symbol,
  1583.  * then do or don't skip to the #endif/#else/#elif depending
  1584.  * on what directive is actually being processed.
  1585.  */
  1586. do_xifdef (buf, limit, op, keyword)
  1587.      U_CHAR *buf, *limit;
  1588.      FILE_BUF *op;
  1589.      struct keyword_table *keyword;
  1590. {
  1591.   HASHNODE *lookup();
  1592.   int skip;
  1593.   FILE_BUF *ip = &instack[indepth - 1];
  1594.  
  1595.   SKIP_WHITE_SPACE (buf);
  1596.   skip = (lookup(buf) == NULL) ^ (keyword->type == T_IFNDEF);
  1597.   conditional_skip (ip, skip, T_IF);
  1598. }
  1599.  
  1600. /*
  1601.  * push TYPE on stack; then, if SKIP is nonzero, skip ahead.
  1602.  */
  1603. static
  1604. conditional_skip (ip, skip, type)
  1605.      FILE_BUF *ip;
  1606.      int skip, type;
  1607. {
  1608.   IF_STACK_FRAME *temp;
  1609.  
  1610.   temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME));
  1611.   temp->fname = ip->fname;
  1612.   temp->lineno = ip->lineno;
  1613.   temp->next = if_stack;
  1614.   if_stack = temp;
  1615.  
  1616.   if_stack->type = type;
  1617.   
  1618.   if (skip != 0) {
  1619.     skip_if_group(ip);
  1620.     return;
  1621.   } else {
  1622.     ++if_stack->if_succeeded;
  1623.     output_line_command(ip, &outbuf);    /* JF */
  1624.   }
  1625. }
  1626.  
  1627. /*
  1628.  * skip to #endif, #else, or #elif.  adjust line numbers, etc.
  1629.  * leaves input ptr at the sharp sign found.
  1630.  */
  1631. static
  1632. skip_if_group(ip)
  1633.      FILE_BUF *ip;
  1634. {
  1635.   register U_CHAR *bp = ip->bufp, *cp;
  1636.   register U_CHAR *endb = ip->buf + ip->length;
  1637.   struct keyword_table *kt;
  1638.   U_CHAR *save_sharp, *skip_to_end_of_comment (), *skip_quoted_string ();
  1639.   IF_STACK_FRAME *save_if_stack = if_stack; /* don't pop past here */
  1640.  
  1641.   while (bp <= endb) {
  1642.     switch (*bp++) {
  1643.     case '/':            /* possible comment */
  1644.       if (*bp == '*') {
  1645.     ip->bufp = ++bp;
  1646.     bp = skip_to_end_of_comment (ip, &ip->lineno);
  1647.       }
  1648.       break;
  1649.     case '\"':
  1650.     case '\'':
  1651.       ip->bufp = bp - 1;
  1652.       bp = skip_quoted_string (ip, NULL);    /* JF was (ip) */
  1653.       break;
  1654.     case '\n':
  1655.       ++ip->lineno;
  1656.       break;
  1657.     case '#':
  1658.       /* # keyword: the # must be first nonblank char on the line */
  1659.       for (cp = bp - 1; cp >= ip->buf; cp--)
  1660.     if (*cp == '\n')
  1661.       break;
  1662.       cp++;            /* skip nl or move back into buffer */
  1663.       SKIP_WHITE_SPACE (cp);
  1664.       if (cp != bp - 1)    /* ????? */
  1665.     break;
  1666.  
  1667.       save_sharp = cp;        /* point at '#' */
  1668.       SKIP_WHITE_SPACE (bp);
  1669.       for (kt = keyword_table; kt->length >= 0; kt++) {
  1670.     IF_STACK_FRAME *temp;
  1671.     if (strncmp(bp, kt->name, kt->length) == 0
  1672.         && !is_idchar[bp[kt->length]]) {
  1673.       switch (kt->type) {
  1674.       case T_IF:
  1675.       case T_IFDEF:
  1676.       case T_IFNDEF:
  1677.         temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME));
  1678.         temp->next = if_stack;
  1679.         if_stack = temp;
  1680.         temp->lineno = ip->lineno;
  1681.         temp->fname = ip->fname;
  1682.         temp->type = kt->type;
  1683.         break;
  1684.       case T_ELSE:
  1685.       case T_ELIF:
  1686.       case T_ENDIF:
  1687.         ip->bufp = save_sharp;
  1688.         if (if_stack == NULL) {
  1689.           U_CHAR msg[50];
  1690.           sprintf (msg, "if-less #%s", kt->name);
  1691.           error (msg);
  1692.           break;
  1693.         }
  1694.         else if (if_stack == save_if_stack)
  1695.           return;        /* found what we came for */
  1696.  
  1697.         if (kt->type != T_ENDIF) {
  1698.           if (if_stack->type == T_ELSE)
  1699.         error ("#else or #elif after #else");
  1700.           if_stack->type = kt->type;
  1701.           break;
  1702.         }
  1703.  
  1704.         temp = if_stack;
  1705.         if_stack = if_stack->next;
  1706.         free (temp);
  1707.         break;
  1708.       }
  1709.     }
  1710.       }
  1711.     }
  1712.   }
  1713.   ip->bufp = bp;
  1714.   ip->lineno = instack->lineno; /* bufp won't be right, though */
  1715.   error ("unterminated #if/#ifdef/#ifndef conditional");
  1716.   /* after this returns, the main loop will exit because ip->bufp
  1717.      now points to the end of the buffer.  I am not sure whether
  1718.      this is dirty or not. */
  1719.   return;
  1720. }
  1721.  
  1722. /*
  1723.  * handle a #else directive.  Do this by just continuing processing
  1724.  * without changing  if_stack ;  this is so that the error message
  1725.  * for missing #endif's etc. will point to the original #if.  It
  1726.  * is possible that something different would be better.
  1727.  */ 
  1728. do_else(buf, limit, op, keyword)
  1729.      U_CHAR *buf, *limit;
  1730.      FILE_BUF *op;
  1731.      struct keyword_table *keyword;
  1732. {
  1733.   register U_CHAR *bp;
  1734.   FILE_BUF *ip = &instack[indepth - 1];
  1735.  
  1736.   if (if_stack == NULL) {
  1737.     error ("if-less #else");
  1738.     return;
  1739.   } else {
  1740.     if (if_stack->type != T_IF && if_stack->type != T_ELIF) {
  1741.       error ("#else after #else");
  1742.       fprintf (stderr, " (matches line %d", if_stack->lineno);
  1743.       if (strcmp(if_stack->fname, ip->fname) != 0)
  1744.     fprintf (stderr, ", file %s", if_stack->fname);
  1745.       fprintf(stderr, ")\n");
  1746.     }
  1747.     if_stack->type = T_ELSE;
  1748.   }
  1749.  
  1750.   if (if_stack->if_succeeded)
  1751.     skip_if_group (ip);
  1752.   else {
  1753.     ++if_stack->if_succeeded;    /* continue processing input */
  1754.     output_line_command(ip, op);    /* JF try to keep line #s right? */
  1755.   }
  1756. }
  1757.  
  1758. /*
  1759.  * unstack after #endif command
  1760.  */
  1761. do_endif(buf, limit, op, keyword)
  1762.      U_CHAR *buf, *limit;
  1763.      FILE_BUF *op;
  1764.      struct keyword_table *keyword;
  1765. {
  1766.   register U_CHAR *bp;
  1767.  
  1768.   if (if_stack == NULL)
  1769.     error ("if-less #endif");
  1770.   else {
  1771.     IF_STACK_FRAME *temp = if_stack;
  1772.     if_stack = if_stack->next;
  1773.     free (temp);
  1774.     /* JF try to keep line #s right? */
  1775.     output_line_command (&instack[indepth - 1], op);
  1776.   }
  1777. }
  1778.  
  1779. /*
  1780.  * Skip a comment, assuming the input ptr immediately follows the
  1781.  * initial slash-star.  Bump line counter as necessary.
  1782.  * (The canonical line counter is &ip->lineno).
  1783.  * Don't use this routine (or the next one) if bumping the line
  1784.  * counter is not sufficient to deal with newlines in the string.
  1785.  */
  1786. U_CHAR *
  1787. skip_to_end_of_comment (ip, line_counter)
  1788.      register FILE_BUF *ip;
  1789.      int *line_counter;        /* place to remember newlines, or NULL */
  1790. {
  1791.   register U_CHAR *limit = ip->buf + ip->length;
  1792.   register U_CHAR *bp = ip->bufp;
  1793.   FILE_BUF *op = &outbuf;    /* JF */
  1794.  
  1795.     /* JF this line_counter stuff is a crock to make sure the
  1796.        comment is only put out once, no matter how many times
  1797.        the comment is skipped.  It almost works */
  1798.   if (put_out_comments && !line_counter) {
  1799.     *op->bufp++ = '/';
  1800.     *op->bufp++ = '*';
  1801.   }
  1802.   while (bp < limit) {
  1803.     if (put_out_comments && !line_counter)
  1804.       *op->bufp++ = *bp;
  1805.     switch (*bp++) {
  1806.     case '\n':
  1807.       if (line_counter != NULL)
  1808.     ++*line_counter;
  1809.       break;
  1810.     case '*':
  1811.       if (*bp == '/') {
  1812.         if (put_out_comments && !line_counter)
  1813.       *op->bufp++ = '/';
  1814.     ip->bufp = ++bp;
  1815.     return bp;
  1816.       }
  1817.       break;
  1818.     }
  1819.   }
  1820.   ip->bufp = bp;
  1821.   return bp;
  1822. }
  1823. /*
  1824.  * skip over a quoted string.  Unlike skip_to_end_of_comment, this
  1825.  * wants ip->bufp at the beginning quote, not after it.  this is so we
  1826.  * can tell what kind of quote to match.  return if unescaped eol is
  1827.  * encountered --- it is probably some sort of error in the input.
  1828.  */
  1829. U_CHAR *
  1830. skip_quoted_string (ip, count_newlines)
  1831.      register FILE_BUF *ip;
  1832.      int count_newlines;
  1833. {
  1834.   register U_CHAR *limit = ip->buf + ip->length;
  1835.   register U_CHAR *bp = ip->bufp;
  1836.   register U_CHAR c, match;
  1837.  
  1838.   match = *bp++;
  1839.   while (bp < limit) {
  1840.     c = *bp++;
  1841.     if (c == '\\') {
  1842.       if (*bp++ == '\n' && count_newlines)
  1843.     ++ip->lineno;
  1844.     } else if (c == '\n') {
  1845.       bp -= 2;            /* whoa!  back up to eol and punt. */
  1846.       break;
  1847.     } else if (c == match)
  1848.       break;
  1849.   }
  1850.   ip->bufp = bp;
  1851.   return bp;
  1852. }
  1853.  
  1854. /*
  1855.  * write out a #line command, for instance, after an #include file.
  1856.  */
  1857. static
  1858. output_line_command (ip, op)
  1859.      FILE_BUF *ip, *op;
  1860. {
  1861.   int len, line_cmd_buf[500];
  1862.  
  1863.   if (ip->fname == NULL)
  1864.     return;
  1865.  
  1866. #ifdef OUTPUT_LINE_COMMANDS
  1867.   sprintf(line_cmd_buf, "#line %d \"%s\"\n", ip->lineno, ip->fname);
  1868. #else
  1869.   sprintf(line_cmd_buf, "# %d \"%s\"\n", ip->lineno, ip->fname);
  1870. #endif
  1871.   len = strlen(line_cmd_buf);
  1872.   check_expand (op, len);
  1873.   if (op->bufp > op->buf && op->bufp[-1] != '\n')    /* JF make sure */
  1874.       *op->bufp++ = '\n';
  1875.   bcopy (line_cmd_buf, op->bufp, len);
  1876.   op->bufp += len;
  1877. }
  1878.  
  1879.  
  1880. /* Expand a macro call.
  1881.    HP points to the symbol that is the macro being called.
  1882.    IP is the input source for reading the arguments of the macro.
  1883.    Send the result of the expansion to OP.
  1884.    EXCESS_NEWLINES_PTR points to an integer;
  1885.    we increment that integer once for each newline swallowed
  1886.    in the process of reading this macro call.  */
  1887.  
  1888. macroexpand (hp, ip, op, excess_newlines_ptr)
  1889.      HASHNODE *hp;
  1890.      FILE_BUF *ip, *op;
  1891.      int *excess_newlines_ptr;
  1892. {
  1893.   FILE_BUF *ip2;
  1894.   int nargs;
  1895.   DEFINITION *defn = hp->value.defn;
  1896.   int newlines_found = 0;
  1897.  
  1898.   /* it might not actually be a macro.  */
  1899.   if (hp->type != T_MACRO)
  1900.     return expand_special_symbol (hp, ip, op);
  1901.  
  1902.   ip2 = &instack[indepth++];
  1903.   bzero (ip2, sizeof (FILE_BUF)); /* paranoia */
  1904.  
  1905.   nargs = defn->nargs;
  1906.  
  1907.   if (nargs >= 0)
  1908.     {
  1909.       register U_CHAR *bp, *xbuf;
  1910.       U_CHAR *skip_macro_argument ();
  1911.       register int i;
  1912.       int xbuf_len;
  1913.       int offset;        /* offset in expansion,
  1914.                    copied a piece at a time */
  1915.       int totlen;        /* total amount of exp buffer filled so far */
  1916.  
  1917.       register struct reflist *ap;
  1918.       struct argptrs { 
  1919.                U_CHAR *argstart;
  1920.                int length;
  1921.              } *args;
  1922.  
  1923.       args = (struct argptrs *) alloca ((nargs + 1) * sizeof (struct argptrs));
  1924.       if (ip->bufp >= ip->buf+ip->length)
  1925.     {            /* JF evil magic to make things work! */
  1926.       ip = &instack[indepth-3];
  1927.     }
  1928.       bp = ip->bufp;
  1929.  
  1930.       /* make sure it really was a macro call. */
  1931.       if (isspace(bp[-1])) {
  1932.     while (isspace (*bp)) {
  1933.       if (*bp == '\n')
  1934.         ++newlines_found;
  1935.       bp++;
  1936.     }
  1937.     if (*bp != '(')
  1938.       goto nope;
  1939.     bp++;            /* skip over the paren */
  1940.       }
  1941.       else if (*(bp-1) != '(')
  1942.     goto nope;
  1943.  
  1944.       for (i = 0; i < nargs; i++) {
  1945.     args[i].argstart = bp;
  1946.     bp = skip_macro_argument(bp, ip, &newlines_found);
  1947.     args[i].length = bp - args[i].argstart;
  1948.     if (*bp == ',')
  1949.       bp++;
  1950.       }
  1951.       args[nargs].argstart = bp;
  1952.       if (*bp++ != ')')
  1953.     goto nope;
  1954.  
  1955.       /* make a rescan buffer with enough room for the pattern plus
  1956.      all the arg strings. */
  1957.       xbuf_len = defn->length + 1;
  1958.       for (ap = defn->pattern; ap != NULL; ap = ap->next)
  1959.     xbuf_len += args[ap->argno - 1].length;
  1960.       xbuf = (U_CHAR *) alloca (xbuf_len);
  1961.  
  1962.       offset = totlen = 0;
  1963.       for (ap = defn->pattern; ap != NULL; ap = ap->next) {
  1964.     bcopy (defn->expansion + offset, xbuf + totlen, ap->nchars);
  1965.     totlen += ap->nchars;
  1966.     offset += ap->nchars;
  1967.  
  1968.     if (ap->argno > 0) {
  1969.       bcopy (args[ap->argno - 1].argstart, xbuf + totlen,
  1970.          args[ap->argno - 1].length);
  1971.       totlen += args[ap->argno - 1].length;
  1972.     }
  1973.  
  1974.     if (totlen > xbuf_len)
  1975.       {
  1976.         /* impossible */
  1977.         error ("cpp impossible internal error: expansion too large");
  1978.         goto nope;        /* this can't happen??? */
  1979.       }
  1980.       }
  1981.  
  1982.       /* if there is anything left after handling the arg list,
  1983.      copy that in too. */
  1984.       if (offset < defn->length) {
  1985.     bcopy (defn->expansion + offset, xbuf + totlen,
  1986.            defn->length - offset);
  1987.     totlen += defn->length - offset;
  1988.       }
  1989.  
  1990.       ip2->buf = xbuf;
  1991.       ip2->length = totlen;
  1992.  
  1993.       /* skip the input over the whole macro call. */
  1994.       ip->bufp = bp;
  1995.  
  1996.     }
  1997.   else
  1998.     {
  1999.       ip2->buf = ip2->bufp = defn->expansion;
  2000.       ip2->length = defn->length;
  2001.     }
  2002.   
  2003.   rescan (ip2, op);
  2004.   --indepth;
  2005.   *excess_newlines_ptr += newlines_found;
  2006.   ip->lineno += newlines_found;
  2007.  
  2008.   return 0;
  2009.  
  2010.  nope:
  2011.   error ("argument mismatch");
  2012.   --indepth;
  2013.   return 1;
  2014. }
  2015.  
  2016. /*
  2017.  * skip a balanced paren string up to the next comma.
  2018.  */
  2019. U_CHAR *
  2020. skip_macro_argument(bp, ip, newlines)
  2021.      U_CHAR *bp;
  2022.      FILE_BUF *ip;
  2023.      int *newlines;
  2024. {
  2025.   int paren = 0;
  2026.   int quotec = 0;
  2027.   
  2028.   while (bp < ip->buf + ip->length) {
  2029.     switch (*bp) {
  2030.     case '(':
  2031.       paren++;
  2032.       break;
  2033.     case ')':
  2034.       if (--paren < 0)
  2035.     return bp;
  2036.       break;
  2037.     case '\n':
  2038.       ++*newlines;
  2039.       break;
  2040.     case '/':
  2041.       if (bp[1] != '*' || bp + 1 >= ip->buf + ip->length)
  2042.     break;
  2043.       bp += 2;
  2044.       while ((bp[0] != '*' || bp[1] != '/')
  2045.          && bp + 1 < ip->buf + ip->length)
  2046.     {
  2047.       if (*bp == '\n') ++*newlines;
  2048.       bp++;
  2049.     }
  2050.       break;
  2051.     case '\'':        /* JF handle quotes right  */
  2052.     case '\"':
  2053.       for (quotec = *bp++; bp < ip->buf + ip->length && *bp != quotec; bp++)
  2054.     {
  2055.       if (*bp == '\\') bp++;
  2056.       if (*bp == '\n')
  2057.         ++*newlines;
  2058.     }
  2059.       break;
  2060.     case ',':
  2061.       if (paren == 0)
  2062.     return bp;
  2063.       break;
  2064.     }
  2065.     bp++;
  2066.   }
  2067.   return bp;
  2068. }
  2069.  
  2070. /*
  2071.  * error - print out message.  also make print on stderr.  Uses stdout
  2072.  * now for debugging convenience.
  2073.  */
  2074. error (msg)
  2075.      U_CHAR *msg;
  2076. {
  2077.   int i;
  2078.   FILE_BUF *ip = NULL;
  2079.  
  2080.   for (i = indepth - 1; i >= 0; i--)
  2081.     if (instack[i].fname != NULL) {
  2082.       ip = &instack[i];
  2083.       break;
  2084.     }
  2085.  
  2086.   if (ip != NULL)
  2087.     fprintf(stdout, "file %s, offset %d (line %d): ",
  2088.         ip->fname, ip->bufp - ip->buf, ip->lineno);
  2089.   fprintf(stdout, "%s\n", msg);
  2090.   return 0;
  2091. }
  2092.  
  2093. /*
  2094.  * if OBUF doesn't have NEEDED bytes after OPTR, make it bigger
  2095.  *    this should be a macro, for speed.
  2096.  * The "expand" in the name of this routine means buffer expansion,
  2097.  * not macro expansion.  It may become necessary to have some hacky
  2098.  * mechanism for flushing out the output buffer if it gets too big.
  2099.  *
  2100.  * As things stand, nothing is ever placed in the output buffer to be
  2101.  * removed again except when it's KNOWN to be part of an identifier,
  2102.  * so flushing and moving down everything left, instead of expanding,
  2103.  * should work ok.
  2104.  */
  2105. U_CHAR *
  2106. check_expand(obuf, needed)
  2107.      register FILE_BUF *obuf;
  2108.      register int needed;
  2109. {
  2110.   register int i;
  2111.   register U_CHAR *p;
  2112.   
  2113.   if (obuf->length - (obuf->bufp - obuf->buf) > needed)
  2114.     return obuf->buf;
  2115.  
  2116.   i = 2 * obuf->length;
  2117.   if (needed >= i)
  2118.     i += (3 * needed) / 2;
  2119.  
  2120.   if ((p = (U_CHAR *) xrealloc (obuf->buf, i)) == NULL)
  2121.     return NULL;
  2122.   obuf->bufp = p + (obuf->bufp - obuf->buf);
  2123.   obuf->buf = p;
  2124.   obuf->length = i;
  2125.  
  2126.   return p;
  2127. }
  2128.   
  2129. /*
  2130.  * install a name in the main hash table, even if it is already there.
  2131.  *   name stops with first non alphanumeric, except leading '#'.
  2132.  * caller must check against redefinition if that is desired.
  2133.  * delete() removes things installed by install() in fifo order.
  2134.  * this is important because of the `defined' special symbol used
  2135.  * in #if, and also if pushdef/popdef directives are ever implemented.
  2136.  */
  2137. HASHNODE *
  2138. install (name, type, value)
  2139.      U_CHAR *name;
  2140.      int type;
  2141.      int value;
  2142.         /* watch out here if sizeof(U_CHAR *) != sizeof (int) */
  2143. {
  2144.   HASHNODE *hp;
  2145.   int i, len = 0, bucket;
  2146.   register U_CHAR *p;
  2147.  
  2148.   p = name;
  2149.   while (is_idchar[*p])
  2150.     p++;
  2151.   len = p - name;
  2152.  
  2153.   i = sizeof (HASHNODE) + len + 1;
  2154.   hp = (HASHNODE *) xmalloc (i);
  2155.   bucket = hashf(name, len, HASHSIZE);
  2156.   hp->bucket_hdr = &hashtab[bucket];
  2157.   hp->next = hashtab[bucket];
  2158.   hashtab[bucket] = hp;
  2159.   hp->prev = NULL;
  2160.   if (hp->next != NULL)
  2161.     hp->next->prev = hp;
  2162.   hp->type = type;
  2163.   hp->length = len;
  2164.   hp->value.ival = value;
  2165.   hp->name = ((U_CHAR *) hp) + sizeof (HASHNODE);
  2166.   bcopy (name, hp->name, len);
  2167.   return hp;
  2168. }
  2169. /*
  2170.  * find the most recent hash node for name name (ending with first
  2171.  * non-identifier char) installed by install
  2172.  */
  2173. HASHNODE *
  2174. lookup (name)
  2175.      U_CHAR *name;
  2176. {
  2177.   register U_CHAR *bp;
  2178.   register HASHNODE *bucket;
  2179.   int len;
  2180.  
  2181.   for (bp = name; is_idchar[*bp]; bp++)
  2182.     ;
  2183.   len = bp - name;
  2184.   bucket = hashtab[hashf(name, len, HASHSIZE)];
  2185.   while (bucket) {
  2186.     if (bucket->length == len && strncmp(bucket->name, name, len) == 0)
  2187.       return bucket;
  2188.     bucket = bucket->next;
  2189.   }
  2190.   return NULL;
  2191. }
  2192.  
  2193. /*
  2194.  * Delete a hash node.  Some weirdness to free junk from macros.
  2195.  * More such weirdness will have to be added if you define more hash
  2196.  * types that need it.
  2197.  */
  2198. delete(hp)
  2199.      HASHNODE *hp;
  2200. {
  2201.   
  2202.   if (hp->prev != NULL)
  2203.     hp->prev->next = hp->next;
  2204.   if (hp->next != NULL)
  2205.     hp->next->prev = hp->prev;
  2206.  
  2207.   /* make sure that the bucket chain header that
  2208.      the deleted guy was on points to the right thing afterwards. */
  2209.   if (hp == *hp->bucket_hdr)
  2210.     *hp->bucket_hdr = hp->next;
  2211.  
  2212.   if (hp->type == T_MACRO) {
  2213.     DEFINITION *d = hp->value.defn;
  2214.     struct reflist *ap, *nextap;
  2215.  
  2216.     for (ap = d->pattern; ap != NULL; ap = nextap) {
  2217.       nextap = ap->next;
  2218.       free (ap);
  2219.     }
  2220.     free (d);
  2221.   }
  2222. }
  2223.  
  2224. /*
  2225.  * return hash function on name.  must be compatible with the one
  2226.  * computed a step at a time, elsewhere
  2227.  */
  2228. int
  2229. hashf(name, len, hashsize)
  2230.      register U_CHAR *name;
  2231.      register int len;
  2232.      int hashsize;
  2233. {
  2234.   register int r = 0;
  2235.   
  2236.   while (len--)
  2237.     r = HASHSTEP(r, *name++);
  2238.   
  2239.   return MAKE_POS(r) % hashsize;
  2240. }
  2241.  
  2242.  
  2243. /*
  2244.  * initialize random junk in the hash table and maybe other places
  2245.  */
  2246. initialize_random_junk()
  2247. {
  2248.   register int i;
  2249.  
  2250.   /*
  2251.    * Set up is_idchar and is_idstart tables.  These should be
  2252.    * faster than saying (is_alpha(c) || c == '_'), etc.
  2253.    * Must do set up these things before calling any routines tthat
  2254.    * refer to them.
  2255.    */
  2256.   for (i = 'a'; i <= 'z'; i++) {
  2257.     ++is_idchar[i - 'a' + 'A'];
  2258.     ++is_idchar[i];
  2259.     ++is_idstart[i - 'a' + 'A'];
  2260.     ++is_idstart[i];
  2261.   }
  2262.   for (i = '0'; i <= '9'; i++)
  2263.     ++is_idchar[i];
  2264.   ++is_idchar['_'];
  2265.   ++is_idstart['_'];
  2266.  
  2267.   /* horizontal space table */
  2268.   ++is_hor_space[' '];
  2269.   ++is_hor_space['\t'];
  2270.  
  2271.   install("__LINE__", T_SPECLINE, 0);
  2272.   install("__DATE__", T_DATE, 0);
  2273.   install("__FILE__", T_FILE, 0);
  2274.   install("__TIME__", T_TIME, 0);
  2275.  
  2276. #ifdef vax
  2277.   make_definition("vax 1");
  2278. #endif
  2279.  
  2280. #ifdef unix
  2281.   make_definition("unix 1");
  2282. #endif
  2283.  
  2284.   /* is there more? */
  2285.   
  2286. }
  2287.  
  2288. /*
  2289.  * process a given definition string, for initialization
  2290.  */
  2291. make_definition(str)
  2292.      U_CHAR *str;
  2293. {
  2294.   FILE_BUF *ip;
  2295.   struct keyword_table *kt;
  2296.  
  2297.   ip = &instack[indepth++];
  2298.   ip->fname = "*Initialization*";
  2299.  
  2300.   ip->buf = ip->bufp = str;
  2301.   ip->length = strlen(str);
  2302.   ip->lineno = 1;
  2303.  
  2304.   for (kt = keyword_table; kt->type != T_DEFINE; kt++)
  2305.     ;
  2306.  
  2307.   /* pass NULL as output ptr to do_define since we KNOW it never
  2308.      does any output.... */
  2309.   do_define (str, str + strlen(str) /* - 1 JF */ , NULL, kt);
  2310.   --indepth;
  2311. }
  2312.  
  2313. /* JF, this does the work for the -U option */
  2314. make_undef(str)
  2315.      U_CHAR *str;
  2316. {
  2317.   FILE_BUF *ip;
  2318.   struct keyword_table *kt;
  2319.  
  2320.   ip = &instack[indepth++];
  2321.   ip->fname = "*undef*";
  2322.  
  2323.   ip->buf = ip->bufp = str;
  2324.   ip->length = strlen(str);
  2325.   ip->lineno = 1;
  2326.  
  2327.   for(kt = keyword_table; kt->type != T_UNDEF; kt++)
  2328.     ;
  2329.  
  2330.   do_undef(str,str + strlen(str) - 1, NULL, kt);
  2331.   --indepth;
  2332. }
  2333.  
  2334.  
  2335. #ifndef BSD
  2336. #ifndef BSTRING
  2337.  
  2338. void
  2339. bzero (b, length)
  2340.      register char *b;
  2341.      register int length;
  2342. {
  2343. #ifdef VMS
  2344.   short zero = 0;
  2345.   long max_str = 65535;
  2346.  
  2347.   while (length > max_str)
  2348.     {
  2349.       (void) LIB$MOVC5 (&zero, &zero, &zero, &max_str, b);
  2350.       length -= max_str;
  2351.       b += max_str;
  2352.     }
  2353.   (void) LIB$MOVC5 (&zero, &zero, &zero, &length, b);
  2354. #else
  2355.   while (length-- > 0)
  2356.     *b++ = 0;
  2357. #endif /* not VMS */
  2358. }
  2359.  
  2360. void 
  2361. bcopy (b1, b2, length)
  2362.      register char *b1;
  2363.      register char *b2;
  2364.      register int length;
  2365. {
  2366. #ifdef VMS
  2367.   long max_str = 65535;
  2368.  
  2369.   while (length > max_str)
  2370.     {
  2371.       (void) LIB$MOVC3 (&max_str, b1, b2);
  2372.       length -= max_str;
  2373.       b1 += max_str;
  2374.       b2 += max_str;
  2375.     }
  2376.   (void) LIB$MOVC3 (&length, b1, b2);
  2377. #else
  2378.   while (length-- > 0)
  2379.     *b2++ = *b1++;
  2380. #endif /* not VMS */
  2381. }
  2382.  
  2383. int
  2384. bcmp (b1, b2, length)    /* This could be a macro! */
  2385.      register char *b1;
  2386.      register char *b2;
  2387.       register int length;
  2388.  {
  2389. #ifdef VMS
  2390.    struct dsc$descriptor_s src1 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b1};
  2391.    struct dsc$descriptor_s src2 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b2};
  2392.  
  2393.    return STR$COMPARE (&src1, &src2);
  2394. #else
  2395.    while (length-- > 0)
  2396.      if (*b1++ != *b2++)
  2397.        return 1;
  2398.  
  2399.    return 0;
  2400. #endif /* not VMS */
  2401. }
  2402. #endif /* not BSTRING */
  2403. #endif /* not BSD */
  2404.  
  2405.  
  2406. void
  2407. fatal (str, arg)
  2408.      char *str, *arg;
  2409. {
  2410.   fprintf (stderr, "%s: ", progname);
  2411.   fprintf (stderr, str, arg);
  2412.   fprintf (stderr, "\n");
  2413.   exit (FATAL_EXIT_CODE);
  2414. }
  2415.  
  2416. void
  2417. perror_with_name (name)
  2418.      char *name;
  2419. {
  2420.   extern int errno, sys_nerr;
  2421.   extern char *sys_errlist[];
  2422.  
  2423.   fprintf (stderr, "%s: ", progname);
  2424.   if (errno < sys_nerr)
  2425.     fprintf (stderr, "%s for %s\n", sys_errlist[errno], name);
  2426.   else
  2427.     fprintf (stderr, "cannot open %s\n", sys_errlist[errno], name);
  2428. }
  2429.  
  2430. void
  2431. pfatal_with_name (name)
  2432.      char *name;
  2433. {
  2434.   perror_with_name (name);
  2435.   exit (FATAL_EXIT_CODE);
  2436. }
  2437.  
  2438.  
  2439. static void
  2440. memory_full ()
  2441. {
  2442.   fatal ("Memory exhausted.");
  2443. }
  2444.  
  2445.  
  2446. char *
  2447. xmalloc (size)
  2448.      int size;
  2449. {
  2450.   extern char *malloc ();
  2451.   register char *ptr = malloc (size);
  2452.   if (ptr != 0) return (ptr);
  2453.   memory_full ();
  2454.   /*NOTREACHED*/
  2455. }
  2456.  
  2457. char *
  2458. xrealloc (old, size)
  2459.      char *old;
  2460.      int size;
  2461. {
  2462.   extern char *realloc ();
  2463.   register char *ptr = realloc (old, size);
  2464.   if (ptr != 0) return (ptr);
  2465.   memory_full ();
  2466.   /*NOTREACHED*/
  2467. }
  2468.  
  2469. char *
  2470. xcalloc (number, size)
  2471.      int number, size;
  2472. {
  2473.   extern char *malloc ();
  2474.   register int total = number * size;
  2475.   register char *ptr = malloc (total);
  2476.   if (ptr != 0)
  2477.     {
  2478.       bzero (ptr, total);
  2479.       return (ptr);
  2480.     }
  2481.   memory_full ();
  2482.   /*NOTREACHED*/
  2483. }
  2484.